function CategoryManager(app, div) {

	var self = this;
	this.view = null;
	this.categories = new Array();
	this.bookId = null;

	$.extend(this, new Cache());

	$.subscribe('categories-request', function(event, caller) {
		caller.updateFn(self.categories);
	});

	this.loadCategories = function(bookId) {
		if(this.view == null) {
			this.view = new CategoryManagerView(this, div, app).init();
			$.subscribe('categories-loaded', function(event, data) {
				self.view.updateCategories(data.items);
			});
		}

		if(bookId !== undefined) {
			this.bookId = bookId;
		}
		app.showProgress('Загрузка категорий ...');
		$.ajax({
			url: 'service/categories/read.txt',
			data: { bookId: bookId },
			async: true,
			cache: false,
			success: function (data, status, xhr) {
				self.categories.length = 0;
				self.cleanCache();
				var response = jQuery.parseJSON(data);
				var map = {};
				var cat;
				$.each(response.items, function(index, category) {
					cat = new Category(category.id, category.name, null);
					cat.parentId = category.parentId;
					map[category.id] = cat;
				});
				for(var id in map) {
					cat = map[id];
					cat.parent = map[cat.parentId];
					self.categories.push(cat);
					self.cache(cat);
				}
				$.publish('categories-loaded', { items: self.categories });
				app.showNotification('Категории загружены', 2000);
			},
			error: function () {
				app.showError('Ошибка при загрузке категорий', 'Не удалось загрузить категории книги');
			}
		});
	};

	this.createCategory = function (name, refCategoryId, position) {
		$.ajax({
			url: 'service/categories/submit.txt',
			data: { name: name, refCategoryId: refCategoryId, position: position },
			async: true,
			cache: false,
			success: function (data, status, xhr) {
				var response = jQuery.parseJSON(data);
				if(response.result) {
					app.showNotification('Категория создана', 3000);
					self.loadCategories(self.bookId);
				} else {
					app.showNotification('Не удалось создать категорию: ' + response.message, 5000);
				}
			},
			error: function () {
				app.showNotification('Не удалось создать категорию', 3000);
			}
		});
	};

	this.updateCategory = function (categoryId, name) {
		$.ajax({
			url: 'service/categories/submit.txt',
			data: { categoryId: categoryId, name: name },
			async: true,
			cache: false,
			success: function (data, status, xhr) {
				var response = jQuery.parseJSON(data);
				if(response.result) {
					app.showNotification('Категория изменена', 3000);
					self.loadCategories(self.bookId);
				} else {
					app.showNotification('Не удалось изменить категорию: ' + response.message, 5000);
				}
			},
			error: function () {
				app.showNotification('Не удалось изменить категорию', 3000);
			}
		});
	};

	this.moveCategory = function(categoryId, targetCategoryId, position, async) {
		var result = false;
		$.ajax({
			url: 'service/categories/move.txt',
			data: { categoryId: categoryId, targetCategoryId: targetCategoryId, position: position },
			async: async,
			cache: false,
			success: function (data, status, xhr) {
				var response = jQuery.parseJSON(data);
				result = response.result;
				if(result) {
					app.showNotification('Категория перемещена', 1000);
				} else {
					app.showNotification('Не удалось переместить категорию: ' + response.message, 5000);
				}
			},
			error: function () {
				app.showNotification('Не удалось переместить категорию', 3000);
				result = false;
			}
		});
		return result;
	};

	this.removeCategory = function (categoryId) {
		$.ajax({
			url: 'service/categories/remove.txt',
			data: { categoryId: categoryId },
			async: true,
			cache: false,
			success: function (data, status, xhr) {
				var response = jQuery.parseJSON(data);
				if(response.result) {
					app.showNotification('Категория удалена', 3000);
					self.loadCategories(self.bookId);
				} else {
					app.showNotification('Не удалось удалить категорию: ' + response.message, 5000);
				}
			},
			error: function () {
				app.showNotification('Не удалось удалить категорию', 3000);
			}
		});
	};
};